home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / TURBOPASCAL WIN / OWLDEMOS.PAK / SHELLDEM.PAS < prev    next >
Pascal/Delphi Source File  |  1992-06-08  |  11KB  |  360 lines

  1. {***************************************************}
  2. {                                                   }
  3. {   Turbo Pascal for Windows                        }
  4. {   Windows 3.1 ShellAPI / Drag-and-Drop            }
  5. {               Demonstration Program               }
  6. {                                                   }
  7. {   Copyright (c) 1992 by Borland International     }
  8. {                                                   }
  9. {***************************************************}
  10.  
  11. program ShellDemo;
  12.  
  13. {
  14.  This demo program implements a simple program-manager type application
  15.  using Drag & Drop and the SHELL API calls.
  16.  
  17.  Open this program on the Windows 3.1 desktop, and then drag files from the
  18.  File Manager onto this application's window.  The dropped-in files will 
  19.  appear as Icons in the window's client area, and double-clicking on those
  20.  Icons will execute the corresponding program.
  21. }
  22.  
  23. uses Strings, WinTypes, WinProcs, WObjects, Win31, ShellAPI, BWCC;
  24.  
  25. {$R SHELLDEM}
  26.  
  27. const
  28.  
  29. { Resource IDs }
  30.  
  31.   id_Menu  = 100;
  32.   id_About = 100;
  33.   id_Instr = 101;   { Instructions }
  34.   id_Icon  = 100;
  35.  
  36. { Menu command IDs }
  37.  
  38.   cm_HelpAbout = 300;
  39.   cm_HelpInstr = 301;
  40.  
  41. type
  42.  
  43. { Filename string }
  44.  
  45.   TFilename = array[0..255] of Char;
  46.  
  47. { Application main window }
  48.  
  49.   PDropTargetWin = ^TDropTargetWin;
  50.   TDropTargetWin = object(TWindow)
  51.     destructor Done; virtual;
  52.  
  53.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  54.     function  GetClassName: PChar; virtual;
  55.     procedure SetupWindow; virtual;
  56.  
  57.     procedure WMDropFiles(var Msg: TMessage);
  58.       virtual wm_First + wm_DropFiles;
  59.  
  60.     procedure CMHelpAbout(var Msg: TMessage);
  61.       virtual cm_First + cm_HelpAbout;
  62.     procedure CMHelpInstructions(var Msg: TMessage);
  63.       virtual cm_First + cm_HelpInstr;
  64.  
  65. { Override this function in descendant classes to change behavior: }
  66.  
  67.     procedure DropAFile(FileName: PChar; DropX, DropY: Integer); virtual;
  68.   end;
  69.  
  70. { Icon Window }
  71.  
  72.   PIconWindow = ^TIconWindow;
  73.   TIconWindow = object(TWindow)
  74.     AppIcon   : HIcon;
  75.     HasOwnIcon: Boolean;  { True if icon found, False if default used }
  76.     Path      : PChar;
  77.     X, Y      : Integer;
  78.  
  79.     constructor Init(AParent: PWindowsObject; ATitle: PChar; DropX, DropY: Integer);
  80.     destructor  Done; virtual;
  81.  
  82.     procedure Paint(PaintDC: HDC; var PaintInfo: TPaintStruct); virtual;
  83.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  84.     function  GetClassName: PChar; virtual;
  85.  
  86.     procedure WMQueryDragIcon(var Msg: TMessage);
  87.       virtual wm_First + wm_QueryDragIcon;
  88.     procedure WMQueryOpen(var Msg: TMessage);
  89.       virtual wm_First + wm_QueryOpen;
  90.     procedure WMSysCommand(var Msg: TMessage);
  91.       virtual wm_First + wm_SysCommand;
  92.   end;
  93.  
  94. { Application object }
  95.  
  96.   TShellApp = object(TApplication)
  97.     procedure InitMainWindow; virtual;
  98.   end;
  99.  
  100. { Initialized globals }
  101.  
  102. const
  103.   DemoTitle: PChar = 'Shell Demo Program';
  104.  
  105. { Global variables }
  106.  
  107. var
  108.   App: TShellApp;
  109.  
  110.  
  111. { TIconWindow Methods }
  112.  
  113. { Constructs an instance of an IconWindow.  These are child windows to the
  114.   main ShellAPI window which represent dropped files.  IconWindows always
  115.   represent themselves as Iconic.  The Icon to be used is extracted from
  116.   the application (as represented by its Title); if none can be found, the
  117.   idi_Question icon is used.  The IconWindow positions itself at the given
  118.   location.
  119. }
  120. constructor TIconWindow.Init(AParent: PWindowsObject; ATitle: PChar; DropX, DropY: Integer);
  121. var
  122.   FileName: PChar;
  123.   Temp    : TFilename;
  124.   ExeHdl  : THandle;
  125. begin
  126.   TWindow.Init(AParent, ATitle);
  127.   Attr.Style := Attr.Style or (ws_Minimize or ws_Child);
  128.  
  129. { Set the Path data field to the full pathname for later use in executing
  130.   the program.  The passed-in title contains the complete path name of the
  131.   file, which we just copy.  Then, strip off just the filename portion, and
  132.   use that as the actual title for the icon.
  133. }
  134.   Path    := StrNew(ATitle);
  135.   FileName:= StrRScan(Path, '\');
  136.  
  137.   if FileName <> nil then
  138.     SetCaption(@FileName[1]);  { Skip past the '\' }
  139.  
  140. { Extract an Icon from the executable file.  If none is found, then just
  141.   use idi_Question.
  142. }
  143.   ExeHdl := FindExecutable(Path, '.\', Temp);
  144.  
  145.   if ExeHdl <= 32 then
  146.     AppIcon := 0
  147.   else
  148.     AppIcon := ExtractIcon(HInstance, Temp, 0);
  149.  
  150.   if AppIcon <= 1 then
  151.   begin
  152.     AppIcon   := LoadIcon(0, idi_Question);
  153.     HasOwnIcon:= True;
  154.   end
  155.   else
  156.     HasOwnIcon:= False;
  157.  
  158. { Set the x/y position of drop (in Parent coordinates).  This is
  159.   not used in this demo app, but is included to support variations
  160.   through writing descendants.
  161. }
  162.   X := DropX;
  163.   Y := DropY;
  164. end;
  165.  
  166. { Destroys an instance of the IconWindow.  Frees the AppIcon (unless the
  167.   standard idi_Question was used), and disposes of the Path name string.
  168. }
  169. destructor TIconWindow.Done;
  170. begin
  171.   if HasOwnIcon then
  172.     FreeResource(AppIcon);
  173.   StrDispose(Path);
  174.   TWindow.Done;
  175. end;
  176.  
  177. { Redefines GetWindowClass to give this application a NULL Icon.  This
  178.   is necessary so that Windows gives this application a chance to paint
  179.   its own icon when the window is Iconic.  When the hIcon field of AWndClass
  180.   is NULL, this window will receive wm_QueryDragIcon messages.
  181. }
  182. procedure TIconWindow.GetWindowClass(var AWndClass: TWndClass);
  183. begin
  184.   TWindow.GetWindowClass(AWndClass);
  185.   AWndClass.hIcon := 0;
  186. end;
  187.  
  188. { Returns the class name of this window.  This is necessary since we
  189.   redefine the inherited GetWindowClass method, above.
  190. }
  191. function TIconWindow.GetClassName: PChar;
  192. begin
  193.   GetClassName := 'TIconWindow';
  194. end;
  195.  
  196. { Responds to double-clicks on the Icon by executing the associated program.
  197.   Windows sends an iconified window a wm_QueryOpen message when
  198.   double-clicked. Overriding here allows us to completely redefine that
  199.   behavior. Uses the Path data field as the name of the program to execute.
  200. }
  201. procedure TIconWindow.WMQueryOpen(var Msg: TMessage);
  202. begin
  203.   ShellExecute(HWindow, nil, Path, '', '.\', sw_ShowNormal);
  204.  
  205.   Msg.Result := 0;  { Indicate that the message was handled }
  206. end;
  207.  
  208. { Returns the application's icon when the iconified window is dragged.  With
  209.   AWndClass.hIcon set to NULL, Windows asks for this whenever the drag is 
  210.   about to happen.
  211. }
  212. procedure TIconWindow.WMQueryDragIcon(var Msg: TMessage);
  213. begin
  214.   Msg.Result := AppIcon;
  215. end;
  216.  
  217. { Captures and filters out some variations on wm_SysCommand to prevent an
  218.   annoying 'beep' on single clicks on the icon.
  219. }
  220. procedure TIconWindow.WMSysCommand(var Msg: TMessage);
  221. begin
  222.   case (Msg.WParam and $FFF0) of
  223.     sc_MouseMenu: Msg.Result := 0;   { Indicate that the message was handled }
  224.     sc_KeyMenu  : Msg.Result := 0;
  225.   else
  226.     DefWndProc(Msg);
  227.   end;
  228. end;
  229.  
  230. { Responds to repaints of the window when requested.  With AWndClass.hIcon
  231.   set to NULL, Windows will let the window paint itself even when iconic.
  232.   NOTE that this is the 'new' way to draw you own icon, as opposed to 
  233.   wm_PaintIcon in Win3.0.
  234. }
  235. procedure TIconWindow.Paint(PaintDC: HDC; var PaintInfo: TPaintStruct);
  236. begin
  237.   DefWindowProc(HWindow, wm_IconEraseBkgnd, PaintDC, 0);
  238.   DrawIcon(PaintDC, 0, 0, AppIcon);
  239. end;
  240.  
  241.  
  242. { TDropTargetWin Methods }
  243.  
  244. { Destroys an instance of the Drop Target window.  Informs Windows that
  245.   this application will no longer accept Drop-File requests, then invokes
  246.   the ancestral destructor to complete the shutdown of the window.
  247. }
  248. destructor TDropTargetWin.Done;
  249. begin
  250.   DragAcceptFiles(HWindow, False);
  251.   TWindow.Done;
  252. end;
  253.  
  254. { Redefines GetWindowClass to give this application its own Icon, and
  255.   to identify the menu for this application.
  256. }
  257. procedure TDropTargetWin.GetWindowClass(var AWndClass: TWndClass);
  258. begin
  259.   TWindow.GetWindowClass(AWndClass);
  260.   AWndClass.hIcon        := LoadIcon(AWndClass.hInstance, MakeIntResource(id_Icon));
  261.   AWndClass.lpszMenuName := MakeIntResource(id_Menu);
  262.   AWndClass.hBrBackground:= GetStockObject(LtGray_Brush);
  263. end;
  264.  
  265. { Returns the class name of this window.  This is necessary since we
  266.   redefine the inherited GetWindowClass method, above.
  267. }
  268. function TDropTargetWin.GetClassName: PChar;
  269. begin
  270.   GetClassName := 'TDropTargetWin';
  271. end;
  272.  
  273. { Completes the initialization of the Icon window, by informing Windows
  274.   that this window will accept Drop-File requests.  This is deferred to
  275.   SetupWindow since it requires a valid window handle.  Note that
  276.   Shell.dll will flip the ws_Ex_AcceptFiles style bit for this window.
  277.  
  278.   Also posts the Instructions dialog automatically upon startup.
  279. }
  280. procedure TDropTargetWin.SetupWindow;
  281. begin
  282.   TWindow.SetupWindow;
  283.   DragAcceptFiles(HWindow, True);
  284.  
  285.   PostMessage(HWindow, wm_Command, cm_HelpInstr, 0);
  286. end;
  287.  
  288. { Responds to the dropping of a file onto this window.  Obtains the
  289.   dropped in file name(s), then calls the DropAFile method for each 
  290.   dropped file name.  The actual handling of the dropped file happens
  291.   there; it is separated from this method for ease of redefinition by
  292.   descendants.
  293. }
  294. procedure TDropTargetWin.WMDropFiles(var Msg: TMessage);
  295. var
  296.   DropPt     : TPoint;
  297.   hDrop      : THandle;
  298.   NumDropped : Integer;
  299.   DroppedName: TFilename;
  300.   I          : Integer;
  301. begin
  302.   hDrop := Msg.WParam;
  303.   DragQueryPoint(hDrop, DropPt);
  304.  
  305. { By passing in exactly these parameters, we get the number of files
  306.   (and directories) being dropped.
  307. }
  308.   NumDropped := DragQueryFile(hDrop, Word(-1), nil, 0);
  309.  
  310. { This time we pass in the 'real' parameters and SHELL.DLL will fill
  311.   in the path to the file (or directory).  Do so for each dropped file.
  312. }
  313.   for I := 0 to NumDropped-1 do
  314.   begin
  315.     DragQueryFile(hDrop, I, DroppedName, SizeOf(DroppedName));
  316.     DropAFile(DroppedName, DropPt.X, DropPt.Y);
  317.   end;
  318.  
  319.   DragFinish(hDrop);
  320. end;
  321.  
  322. { Actually handles the dropping of a file at a given point, by creating the
  323.   TIconWindow to represent that file.  Descendant classes can alter the be-
  324.   havior of this application by simply redefining this method.
  325. }
  326. procedure TDropTargetWin.DropAFile(FileName: PChar; DropX, DropY: Integer);
  327. begin
  328.   Application^.MakeWindow(New(PIconWindow, Init(@Self, FileName, DropX, DropY)));
  329. end;
  330.  
  331. { Posts the About Box for the Shell API Demo.
  332. }
  333. procedure TDropTargetWin.CMHelpAbout(var Msg: TMessage);
  334. begin
  335.   Application^.ExecDialog(New(PDialog, Init(@Self, PChar(id_About))));
  336. end;
  337.  
  338. { Posts the Instructions Box for the Shell API Demo.
  339. }
  340. procedure TDropTargetWin.CMHelpInstructions(var Msg: TMessage);
  341. begin
  342.   Application^.ExecDialog(New(PDialog, Init(@Self, PChar(id_Instr))));
  343. end;
  344.  
  345.  
  346. { TShellApp Methods }
  347.  
  348. procedure TShellApp.InitMainWindow;
  349. begin
  350.   MainWindow := New(PDropTargetWin, Init(nil, Application^.Name));
  351. end;
  352.  
  353. { Main program }
  354.  
  355. begin
  356.   App.Init(DemoTitle);
  357.   App.Run;
  358.   App.Done;
  359. end.
  360.